#include "control.h"
#include "javascript.h"

namespace javaScript
{
    std::vector<std::string> getArguments(JSContextRef ctx, size_t argc, const JSValueRef argv[])
    {
        std::vector<std::string> arguments;
        if(argc>0)
        {
            for(unsigned int i=0; i< argc; i++)
            {
                if(JSValueIsString(ctx,argv[i]))
                {
                    JSValueRef jsException = NULL;
                    JSStringRef jstring = JSValueToStringCopy(ctx, argv[i], &jsException);
                    size_t length = JSStringGetMaximumUTF8CStringSize(jstring);
                    char* buffer = new char[length];
                    JSStringGetUTF8CString(jstring, buffer, length);
                    arguments.push_back(std::string(buffer));
                    delete[] buffer;
                }
            }
        }
        return arguments;
    }
    JSValueRef jstring(JSContextRef ctx, std::string string)
    {
        JSStringRef str = JSStringCreateWithUTF8CString(string.c_str());
        JSValueRef  val = JSValueMakeString(ctx, str);
        JSStringRelease(str);
        return val;
    }
    JSValueRef isCommand(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        for(unsigned int i=0; i <Control::Instance()->commands.size(); i++)
        {
            if(args[0] == Control::Instance()->commands[i].name)
            return jstring(ctx, Control::Instance()->commands[i].usage);
        }
        return jstring(ctx, "invalid");
    }

    JSValueRef shelfReportCaps(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        //if(Control::Instance()->getWebWidgetByJSContext(ctx) != NULL)
        int id = atoi(args[3].c_str());
        Control::Instance()->webviews[id]->addCapability(args[0], args[1], args[2]);
        Control::Instance()->webviews[id]->notifyCapabilities();
        std::cout << "new capability registered: " << args[0] << " " << args[1] << " " << args[2] << "\n";
        return jstring(ctx, "capability registered");
    }

    JSValueRef switchShelf(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "<b>";
        int shelfID = 0;
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        shelfID = atoi(args[0].c_str());
        if (shelfID == Control::Instance()->notebook.get_current_page()) return jstring(ctx, "we're already there!");
        if(shelfID > Control::Instance()->webviews.size()-1) return jstring(ctx, "no such shelf!");
        std::cout <<"switching shelf to: " << shelfID << "\n";
        Control::Instance()->notebook.set_current_page(int(shelfID));
        Control::Instance()->Shelf_consoleView->script("setPromptName('"+Control::Instance()->webviews[int(shelfID)]->getName()+"')");
        Control::Instance()->webviews[shelfID]->notifyCapabilities();
        returnString += Control::Instance()->webviews[shelfID]->getTitle();
        returnString += "</b>";
        return jstring(ctx, returnString.c_str());
    }

    JSValueRef pluginSays(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        std::cout << "plugin said: " << args[0] << "\n";
        Control::Instance()->getPluginByName(args[1])->put(args[0]);
        return jstring(ctx, "handled");
    }

    JSValueRef loadPlugin(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        Control::Instance()->plug(args[0]);
        return jstring(ctx, "plugin loaded");
    }

    JSValueRef listShelves(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::stringstream returnString;// = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        for(unsigned int i = 0;i < Control::Instance()->webviews.size(); i++)
        {
            returnString << "<a href=\"javascript:switchShelf('" << i << "')\">" << "[" << i << "] <img src='" << Control::Instance()->getFavicon(Control::Instance()->webviews[i]->getURI());
            returnString << "' width=16 height=16> <b>" << Control::Instance()->webviews[i]->getName();
            returnString << "</b> <i>" << Control::Instance()->webviews[i]->getTitle() << "</i></a><br>";
        }
        return jstring(ctx, returnString.str());
    }

    JSValueRef shelfInfo(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        int current = Control::Instance()->getCurrentShelf();
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        returnString += "<img src='";
        returnString += Control::Instance()->getFavicon(Control::Instance()->webviews[current]->getURI());
        returnString += "' width=16 height=16> <b>";
        returnString += Control::Instance()->webviews[current]->getName();
        returnString += "</b> <br>title: <i>";
        returnString += Control::Instance()->webviews[current]->getTitle();
        returnString += "</i><br>url: <i>";
        returnString += Control::Instance()->webviews[current]->getURI();
        returnString += "</i><br>";
        returnString += Control::Instance()->webviews[current]->listCapabilities();
        return jstring(ctx, returnString);
    }

    JSValueRef openInShelf(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::cout << "openening in current shelf!\n";
        std::string returnString = "opening ";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        std::string favicon;
        int current = Control::Instance()->getCurrentShelf();
        if(args[0].rfind("/")>7)
        {
            favicon = args[0].substr(0, args[0].rfind("/") + 1) + "favicon.ico";
        }
        else
        {
            favicon = args[0] + "/favicon.ico";
        }
        returnString += "<img src='";
        returnString += Control::Instance()->getFavicon(favicon);
        returnString += "' width=16 height=16> ";
        returnString += args[0];
        std::string name = Control::Instance()->webviews[current]->open(args[0]);
        Control::Instance()->Shelf_consoleView->script(std::string("setPromptName('")+name+std::string("');"));
        return jstring(ctx, returnString);
    }

    JSValueRef isURI(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        std::string uri = "http://www.google.com/ig";
        if(uri.find(args[0]) != std::string::npos)
        {
            return jstring(ctx,uri);
        }
        return jstring(ctx, "invalid");
    }

    JSValueRef newShelf(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        std::string uri = "about:blank";
        if(argc > 0)
        {
            uri = std::string(args[0]);
        }

        Control::Instance()->newShelf(uri);

        //std::string name = Control::Instance()->Shelf_webView->open(args[0]);
        //Control::Instance()->Shelf_consoleView->script(std::string("setPromptName('")+name+std::string("');"));

        return jstring(ctx, "opening new shelf");
    }

    JSValueRef hideConsole(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::string returnString = "";
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        if(args[0] == "hide")
        {
            Control::Instance()->Shelf_consoleView->getWidget()->set_size_request(-1, 25);
            returnString = "hidden";
        }
        else
        {
            Control::Instance()->Shelf_consoleView->getWidget()->set_size_request(-1, Control::Instance()->consoleSize);
            returnString = "shown";
        }
        return jstring(ctx, returnString);
    }

    JSValueRef setConsoleSize(JSContextRef ctx, JSObjectRef func, JSObjectRef self, size_t argc, const JSValueRef argv[], JSValueRef* exception)
    {
        std::vector<std::string> args = getArguments(ctx, argc, argv);
        std::string returnString = "";
        std::cout <<"got args: "<<args.size()<<"\n";
        if(args[0] == "small")
        {
            Control::Instance()->consoleSize = 100;
            Control::Instance()->Shelf_consoleView->getWidget()->set_size_request(-1, 100);
            returnString = "console size: small";
        }
        if(args[0] == "big")
        {
            Control::Instance()->consoleSize = 300;
            Control::Instance()->Shelf_consoleView->getWidget()->set_size_request(-1, 300);
            returnString = "console size: big";
        }
        if(args[0] == "huge")
        {
            Control::Instance()->consoleSize = 600;
            Control::Instance()->Shelf_consoleView->getWidget()->set_size_request(-1, 600);
            returnString = "console size: huge";
        }
        if(returnString == "") returnString = "Unknown size request. Please use only small, big or huge";
        JSStringRef str = JSStringCreateWithUTF8CString(returnString.c_str());
        JSValueRef  val = JSValueMakeString(ctx, str);
        JSStringRelease(str);
        return val;
    }

}
